use pest::Parser;
use pest_derive::Parser;

#[derive(Parser)]
#[grammar = "lexer.pest"]
pub struct SysYParser;

#[derive(Debug, Clone)]
pub struct Token {
    pub token_type: String,
    pub text: String,
    pub line: usize,
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, Vec<String>> {
    // 先尝试用Pest解析，如果成功就直接返回
    match SysYParser::parse(Rule::program, input) {
        Ok(mut pairs) => {
            let mut tokens = Vec::new();
            let program_pair = pairs.next().unwrap();
            
            for pair in program_pair.into_inner() {
                if pair.as_rule() == Rule::EOI {
                    break;
                }
                
                let line = pair.line_col().0;
                let text = pair.as_str();
                
                let token_type = match pair.as_rule() {
                    Rule::const_kw => "CONST".to_string(),
                    Rule::int_kw => "INT".to_string(),
                    Rule::void_kw => "VOID".to_string(),
                    Rule::if_kw => "IF".to_string(),
                    Rule::else_kw => "ELSE".to_string(),
                    Rule::while_kw => "WHILE".to_string(),
                    Rule::break_kw => "BREAK".to_string(),
                    Rule::continue_kw => "CONTINUE".to_string(),
                    Rule::return_kw => "RETURN".to_string(),
                    Rule::plus => "PLUS".to_string(),
                    Rule::minus => "MINUS".to_string(),
                    Rule::mul => "MUL".to_string(),
                    Rule::div => "DIV".to_string(),
                    Rule::mod_op => "MOD".to_string(),
                    Rule::assign => "ASSIGN".to_string(),
                    Rule::eq => "EQ".to_string(),
                    Rule::neq => "NEQ".to_string(),
                    Rule::lt => "LT".to_string(),
                    Rule::gt => "GT".to_string(),
                    Rule::le => "LE".to_string(),
                    Rule::ge => "GE".to_string(),
                    Rule::not => "NOT".to_string(),
                    Rule::and => "AND".to_string(),
                    Rule::or => "OR".to_string(),
                    Rule::l_paren => "L_PAREN".to_string(),
                    Rule::r_paren => "R_PAREN".to_string(),
                    Rule::l_brace => "L_BRACE".to_string(),
                    Rule::r_brace => "R_BRACE".to_string(),
                    Rule::l_bracket => "L_BRACKT".to_string(),
                    Rule::r_bracket => "R_BRACKT".to_string(),
                    Rule::comma => "COMMA".to_string(),
                    Rule::semicolon => "SEMICOLON".to_string(),
                    Rule::ident => "IDENT".to_string(),
                    Rule::integer_const => "INTEGER_CONST".to_string(),
                    _ => continue,
                };
                
                let token_text = if token_type == "INTEGER_CONST" {
                    convert_integer_to_decimal(text)
                } else {
                    text.to_string()
                };
                
                tokens.push(Token {
                    token_type,
                    text: token_text,
                    line,
                });
            }
            
            Ok(tokens)
        },
        Err(_) => {
            // 如果Pest解析失败，进行逐字符手动扫描来找出所有错误
            scan_for_all_errors(input)
        }
    }
}

fn scan_for_all_errors(input: &str) -> Result<Vec<Token>, Vec<String>> {
    let mut errors = Vec::new();
    let mut tokens = Vec::new();
    let lines: Vec<&str> = input.lines().collect();
    
    for (line_idx, line) in lines.iter().enumerate() {
        let line_num = line_idx + 1;
        let mut chars: Vec<char> = line.chars().collect();
        let mut pos = 0;
        
        while pos < chars.len() {
            // 跳过空白字符
            if chars[pos].is_whitespace() {
                pos += 1;
                continue;
            }
            
            // 跳过行注释
            if pos + 1 < chars.len() && chars[pos] == '/' && chars[pos + 1] == '/' {
                break; // 跳到行末
            }
            
            // 跳过块注释的开始（简化处理）
            if pos + 1 < chars.len() && chars[pos] == '/' && chars[pos + 1] == '*' {
                pos += 2;
                // 寻找块注释结束
                while pos + 1 < chars.len() {
                    if chars[pos] == '*' && chars[pos + 1] == '/' {
                        pos += 2;
                        break;
                    }
                    pos += 1;
                }
                continue;
            }
            
            let start_pos = pos;
            let mut token_found = false;
            
            // 尝试匹配各种token
            if let Some((token_type, token_text, new_pos)) = try_match_token(&chars, pos) {
                tokens.push(Token {
                    token_type,
                    text: token_text,
                    line: line_num,
                });
                pos = new_pos;
                token_found = true;
            }
            
            if !token_found {
                // 找到无效字符，记录错误但继续扫描
                let invalid_char = chars[pos];
                errors.push(format!("Error type A at Line {}:Invalid token '{}'", line_num, invalid_char));
                pos += 1; // 跳过无效字符继续扫描
            }
        }
    }
    
    if errors.is_empty() {
        Ok(tokens)
    } else {
        Err(errors)
    }
}

fn try_match_token(chars: &[char], pos: usize) -> Option<(String, String, usize)> {
    if pos >= chars.len() {
        return None;
    }
    
    // 尝试匹配双字符操作符
    if pos + 1 < chars.len() {
        let two_char = format!("{}{}", chars[pos], chars[pos + 1]);
        match two_char.as_str() {
            "==" => return Some(("EQ".to_string(), "==".to_string(), pos + 2)),
            "!=" => return Some(("NEQ".to_string(), "!=".to_string(), pos + 2)),
            "<=" => return Some(("LE".to_string(), "<=".to_string(), pos + 2)),
            ">=" => return Some(("GE".to_string(), ">=".to_string(), pos + 2)),
            "&&" => return Some(("AND".to_string(), "&&".to_string(), pos + 2)),
            "||" => return Some(("OR".to_string(), "||".to_string(), pos + 2)),
            _ => {}
        }
    }
    
    // 尝试匹配单字符操作符和分隔符
    match chars[pos] {
        '+' => return Some(("PLUS".to_string(), "+".to_string(), pos + 1)),
        '-' => return Some(("MINUS".to_string(), "-".to_string(), pos + 1)),
        '*' => return Some(("MUL".to_string(), "*".to_string(), pos + 1)),
        '/' => return Some(("DIV".to_string(), "/".to_string(), pos + 1)),
        '%' => return Some(("MOD".to_string(), "%".to_string(), pos + 1)),
        '=' => return Some(("ASSIGN".to_string(), "=".to_string(), pos + 1)),
        '<' => return Some(("LT".to_string(), "<".to_string(), pos + 1)),
        '>' => return Some(("GT".to_string(), ">".to_string(), pos + 1)),
        '!' => return Some(("NOT".to_string(), "!".to_string(), pos + 1)),
        '(' => return Some(("L_PAREN".to_string(), "(".to_string(), pos + 1)),
        ')' => return Some(("R_PAREN".to_string(), ")".to_string(), pos + 1)),
        '{' => return Some(("L_BRACE".to_string(), "{".to_string(), pos + 1)),
        '}' => return Some(("R_BRACE".to_string(), "}".to_string(), pos + 1)),
        '[' => return Some(("L_BRACKT".to_string(), "[".to_string(), pos + 1)),
        ']' => return Some(("R_BRACKT".to_string(), "]".to_string(), pos + 1)),
        ',' => return Some(("COMMA".to_string(), ",".to_string(), pos + 1)),
        ';' => return Some(("SEMICOLON".to_string(), ";".to_string(), pos + 1)),
        _ => {}
    }
    
    // 尝试匹配数字常量
    if chars[pos].is_ascii_digit() {
        let mut end_pos = pos;
        let mut number_str = String::new();
        
        // 十六进制
        if pos + 1 < chars.len() && chars[pos] == '0' && (chars[pos + 1] == 'x' || chars[pos + 1] == 'X') {
            end_pos = pos + 2;
            while end_pos < chars.len() && chars[end_pos].is_ascii_hexdigit() {
                end_pos += 1;
            }
            if end_pos > pos + 2 { // 确保有实际的十六进制数字
                number_str = chars[pos..end_pos].iter().collect();
                let decimal_value = convert_integer_to_decimal(&number_str);
                return Some(("INTEGER_CONST".to_string(), decimal_value, end_pos));
            }
        }
        // 八进制或十进制
        else {
            while end_pos < chars.len() && chars[end_pos].is_ascii_digit() {
                end_pos += 1;
            }
            number_str = chars[pos..end_pos].iter().collect();
            let decimal_value = convert_integer_to_decimal(&number_str);
            return Some(("INTEGER_CONST".to_string(), decimal_value, end_pos));
        }
    }
    
    // 尝试匹配标识符或关键字
    if chars[pos].is_ascii_alphabetic() || chars[pos] == '_' {
        let mut end_pos = pos;
        while end_pos < chars.len() && (chars[end_pos].is_ascii_alphanumeric() || chars[end_pos] == '_') {
            end_pos += 1;
        }
        
        let identifier: String = chars[pos..end_pos].iter().collect();
        let token_type = match identifier.as_str() {
            "const" => "CONST",
            "int" => "INT",
            "void" => "VOID",
            "if" => "IF",
            "else" => "ELSE",
            "while" => "WHILE",
            "break" => "BREAK",
            "continue" => "CONTINUE",
            "return" => "RETURN",
            _ => "IDENT",
        };
        
        return Some((token_type.to_string(), identifier, end_pos));
    }
    
    None
}

fn convert_integer_to_decimal(text: &str) -> String {
    if text.starts_with("0x") || text.starts_with("0X") {
        // Hexadecimal
        let hex_part = &text[2..];
        match i64::from_str_radix(hex_part, 16) {
            Ok(value) => value.to_string(),
            Err(_) => text.to_string(),
        }
    } else if text.starts_with('0') && text.len() > 1 && text.chars().all(|c| c.is_ascii_digit()) {
        // Octal
        match i64::from_str_radix(text, 8) {
            Ok(value) => value.to_string(),
            Err(_) => text.to_string(),
        }
    } else {
        // Decimal
        text.to_string()
    }
}